
#include "bRegex.h"
#include "bChunk.h"
#include <iostream>
#include <cctype>

unsigned long int Regex::Regex::findChar(const char* ptr, const char c, unsigned long int size)
{
	unsigned long int i=0;
	while(i<size)
	{
		bool escaped=ptr[i++]=='\\';
		if(escaped)
			continue;
		else if(ptr[i]==c||(!caseSensitive&&toupper(ptr[i])==toupper(c)))
			return i;
	}
	return 0;
}

Regex::Regex::Regex(const char* exp)
{
	unsigned long int i = 0,end=strlen(exp),constPoint = 0;
	bool unescaped = true;
	while(i<end)
	{
		if(unescaped)
		{
			unsigned long int endPoint = 0;
			if(exp[i]=='(')
			{
				endPoint = findChar(exp+i,')',end-i);
				if(i-constPoint>0)
					chunks.append(new ConstChunk(exp+constPoint,i-constPoint));
				constPoint = i + endPoint + 1;
				chunks.append(new GroupChunk(exp+i,endPoint));
			}
			else if(exp[i] == '[')
			{
				endPoint = findChar(exp+i,']',end-i);
				if(i-constPoint>0)
					chunks.append(new ConstChunk(exp+constPoint,i-constPoint));
				constPoint = i + endPoint + 1;
				chunks.append(new CharClassChunk(exp+i,endPoint));
			}
			else if(exp[i] == '$')
			{
				chunks.append(new TerminateChunk());
			}
			else if(exp[i] == '?' || exp[i] == '*' || exp[i] == '+')
			{
				if(i-constPoint>0)
					chunks.append(new ConstChunk(exp+constPoint,i-constPoint));
				constPoint = i + 1;
				chunks[chunks.length()-1]->modify(new Repetition(exp+i));
			}
			else if(exp[i] == '{')
			{
				endPoint = findChar(exp+i,'}',end-i);
				if(i-constPoint>0)
					chunks.append(new ConstChunk(exp+constPoint,i-constPoint));
				constPoint = i + endPoint + 1;
				//chunks[chunks.length()-1]->modify(new RangeRepeat(exp+i,endPoint));
			}
			i+=endPoint;
		}
		unescaped = exp[i++]!='\\';
	}
}

Regex::Regex::~Regex(void)
{
}

const Regex::Result Regex::Regex::match(const char* check,bool ignoreExceptions)
{
	unsigned long int pos = 0;
	for(auto obj(chunks.begin()),end(chunks.end());obj<end;obj++)
	{
		Chunk& c = *obj->object();
		unsigned long int adv=0;
		std::cout << "Trying " << obj->object() << std::endl;
		if(ignoreExceptions)
		{
			adv = c(check,pos);
		} else try {
			adv = c(check,pos);
		} catch ( std::exception e) {
			std::cout << "Failed:\n\t" << e.what() << std::endl;
			return Result(false,pos);
		}
		pos += adv;
		std::cout << "Success. Advance " << adv << " chars." << std::endl;
	}
	return Result(true,pos);
}